package com.nhim.cms.admin.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTree;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.TreeViewModel;
import com.nhim.cms.admin.client.style.Styles;
import com.nhim.cms.admin.shared.NhimCMSAdminRequestFactory;

public class AdministrationTree extends Composite {

	/**
	 * Custom listener for this widget.
	 */
	public interface Listener {

		/**
		 * Called when the user selects a tree item.
		 * 
		 * @param category
		 *            the selected category
		 * @param menu item
		 *            the selected node
		 */
		void onSelection(String category, String menuItem);
	}

	interface Template extends SafeHtmlTemplates {
		@Template("<span class=\"{0}\">{1}</span>")
		SafeHtml span(String classes, String userName);
	}

	/**
	 * A {@link AbstractCell} that represents an {@link MenuItem}.
	 */
	private class MenuCell extends  AbstractCell<MenuItem> 
	{

		private final String usernameStyle = Styles.common()
				.usernameTreeItem();
		private final String usernameStyleSelected = Styles.common()
				.usernameTreeItemSelected();

		@Override
		public boolean dependsOnSelection() {
			return true;
		}

		@Override
		public void render(Context context, MenuItem value,
				SafeHtmlBuilder sb) {
			if (value != null) {
				StringBuilder classesBuilder = new StringBuilder(
						usernameStyle);
				if (lastMenuItem != null
						&& lastMenuItem.getId().equals(value.getId())) {
					classesBuilder.append(" ").append(
							usernameStyleSelected);
				}

				sb.appendEscaped(value.getDisplayName());
				sb.appendHtmlConstant("<br>");
			}
			if (template == null) {
				template = GWT.create(Template.class);
			}
		}
	}

	/**
	 * The {@link ListDataProvider} used for menu lists.
	 */
	private class MenuListDataProvider extends AsyncDataProvider<MenuItem> {

		private final String category;

		public MenuListDataProvider(String category) {
			super(null);
			this.category = category;
		}

		@Override
		public void addDataDisplay(HasData<MenuItem> display) {
			super.addDataDisplay(display);

			updateRowCount(getItemCountByCategory(category), true);
		}

		public int getItemCountByCategory(String category) {
			if(category.equalsIgnoreCase("Global Settings"))
				return 6;
			if(category.equalsIgnoreCase("Templates"))
				return 5;
			return 1;
		}

		public List<MenuItem> getMenuItemsByCategory(String category) {
			
			if(category.equalsIgnoreCase("Global Settings"))
				return getGlobalSettingsMenuItems();
			if(category.equalsIgnoreCase("Templates"))
				return gettemplatesMenuItems();
			return null;
		}
		private List<MenuItem> gettemplatesMenuItems()
		{
			List<MenuItem> items = new ArrayList<MenuItem>();
			MenuItem item;
			
			//Content Template
			item = new MenuItem(51,"Content Template");
			items.add(item);
			
			//Group Template
			item = new MenuItem(52,"Group Template");
			items.add(item);
			
			//Site Template
			item = new MenuItem(53,"Site Template");
			items.add(item);
			
			//Email Template
			item = new MenuItem(54,"Email Template");
			items.add(item);
			
			//Form Template
			item = new MenuItem(55,"Form Template");
			items.add(item);
			
			return items;
		}
		private List<MenuItem> getGlobalSettingsMenuItems()
		{
			List<MenuItem> items = new ArrayList<MenuItem>();
			MenuItem item;
			
			//Element Definition
			item = new MenuItem(41,"Element Definition");
			items.add(item);
			
			// Content Type
			item = new MenuItem(42,"Content Type");
			items.add(item);
			
			//Workflow
			item = new MenuItem(43,"Workflow");
			items.add(item);
			
			//Custom Widget
			item = new MenuItem(44,"Custom Widget");
			items.add(item);
			
			//Flex table
			item = new MenuItem(45,"Flex Table");
			items.add(item);
		
			//URLRewrite
			item = new MenuItem(46,"Urlrewrite");
			items.add(item);
			
			return items;
		}

		@Override
		protected void onRangeChanged(HasData<MenuItem> view) {

			updateRowData(0, getMenuItemsByCategory(category));
		}
	}

	/**
	 * The {@link TreeViewModel} used to browse expense reports.
	 */
	private class MenuTreeViewModel implements TreeViewModel {

		/**
		 * The category cell singleton.
		 */
		private final Cell<String> categoryCell = new TextCell();

		/**
		 * The {@link MenuItemCell} singleton.
		 */
		private final MenuCell menuCell = new MenuCell();

		public <T> NodeInfo<?> getNodeInfo(T value) {
			if (value == null) {
				// Top level.
				return new DefaultNodeInfo<String>(categories, categoryCell,
						selectionModel, null);
			} else if (value instanceof String) {
				// Second level.
				MenuListDataProvider dataProvider = new MenuListDataProvider(
						(String) value);
				return new DefaultNodeInfo<MenuItem>(dataProvider, menuCell,
						selectionModel, null);
			}

			return null;
		}

		/**
		 * @return true if the object is a department
		 */
		public boolean isCategory(Object value) {
			List<String> list = categories.getList();
			String string = value.toString();
			return list.contains(string);
		}

		public boolean isLeaf(Object value) {
			return value != null && (!isCategory(value));
		}
	}

	private static Template template;

	/**
	 * The data provider that provides departments.
	 */
	private final ListDataProvider<String> categories = new ListDataProvider<String>();

	/**
	 * The last selected department.
	 */
	private String lastCategory;

	/**
	 * The last selected MenuItem.
	 */
	private MenuItem lastMenuItem;

	/**
	 * The listener of this widget.
	 */
	private Listener listener;

	/**
	 * The factory used to send requests.
	 */
	private final NhimCMSAdminRequestFactory requestFactory;

	ProvidesKey<Object> keyProvider = new ProvidesKey<Object>() {

		public Object getKey(Object item) {
			if (item instanceof MenuItem) {
				return ((MenuItem) item).getDisplayName();
			}
			return item;
		}
	};
	/**
	 * The shared {@link SingleSelectionModel}.
	 */
	private final SingleSelectionModel<Object> selectionModel = new SingleSelectionModel<Object>(
			keyProvider);

	/**
	 * The main widget.
	 */
	private CellTree tree;

	public AdministrationTree(NhimCMSAdminRequestFactory requestFactory) {
		this.requestFactory = requestFactory;

		// Initialize the departments.
		List<String> departmentList = categories.getList();
		for (String category : NhimCMSAdminApp.ADMINISTRATIONMENU) {
			departmentList.add(category);
		}

		// Initialize the widget.
		createTree();
		initWidget(tree);
		getElement().getStyle().setOverflow(Overflow.AUTO);
	}

	public void setListener(Listener listener) {
		this.listener = listener;
	}

	/**
	 * Create the {@link CellTree}.
	 */
	private void createTree() {
		final MenuTreeViewModel model = new MenuTreeViewModel();

		// Listen for selection. We need to add this handler before the
		// CellBrowser
		// adds its own handler.
		selectionModel
				.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
					public void onSelectionChange(SelectionChangeEvent event) {
						Object selected = selectionModel.getSelectedObject();
						if (selected == null) {
							lastMenuItem = null;
							lastCategory = "";
						} else if (selected instanceof MenuItem) {
							lastMenuItem = (MenuItem) selected;
						} else if (selected instanceof String) {
							lastMenuItem = null;

							lastCategory = (String) selected;
						}

						if (listener != null) {
							listener.onSelection(
									lastCategory,
									lastMenuItem == null ? null : lastMenuItem
											.getDisplayName());
						}
					}
				});

		// Create a CellBrowser.
		tree = new CellTree(model, null);
		tree.setAnimationEnabled(true);
	}
}
